//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;

namespace OpenLS.Spreadsheet.Collections
{
    class Int32Dictionary<TValue>: IDictionary<int, TValue> where TValue: class
    {
        IFrugalDictionary<TValue> _imp = new SingleItemDictionary<TValue>();
        #region IDictionary<int,TValue> Members
#if DEBUG
        [ContractInvariantMethod]
        private void ObjectInvariant()
        {
         //   int count = 0;
           // foreach (int i in this.Keys)
             //   count++;
          //  if (Count != count)
           // {
             //   count = 0;
             //   foreach (int i in this.Keys)
             //       count++;
           // }
           // Contract.Assert(Count == count);
           // Contract.Assert(Count == count);
           // TValue value;
           // Contract.Assert(Enumerable.All(Keys, i => TryGetValue(i, out value)));
//            foreach (int i in Keys)
  //              Contract.Assert(TryGetValue(i, out value));
#if DEBUG
            //foreach (int i in Keys)
           // {
         //       TryGetValue(i, out value);
       //         Contract.Assert(object.Equals(this[i], value));
       //     }
#endif
        //\\    Contract.Invariant(Enumerable.All( Keys, i => ContainsKey(i)));
//            foreach (int i in Keys)
  //              Debug.Assert(ContainsKey(i));
        }
#endif
        public void Add(int key, TValue value)
        {
            Contract.Requires(!ContainsKey(key));
            IFrugalDictionary<TValue> newDic = _imp.TryAddValue(key, value);
            if (newDic == null)
            {
                return;
            }
            transferContentTo(newDic);
            _imp = newDic;
            Add(key, value);
            
        }

        private void transferContentTo(IFrugalDictionary<TValue> newDic)
        {
            IFrugalDictionary<TValue> dummy;
            foreach (int oldKey in _imp)
            {
                TValue oldValue;
                bool b = _imp.TryGetValue(oldKey, out oldValue);
                Contract.Assert(b);
                dummy = newDic.TryAddValue(oldKey, oldValue);
                Contract.Assert(dummy == null);
            }
        }

        public bool ContainsKey(int key)
        {
            TValue value;
            return _imp.TryGetValue(key, out value);
        }

        public ICollection<int> Keys
        {
            get { return new KeyCollection(this._imp); }
        }
        class KeyCollection : ICollection<int>
        {
            public KeyCollection(IFrugalDictionary<TValue> dic)
            {
                this.dic = dic;
            }
            IFrugalDictionary<TValue> dic;
            #region ICollection<int> Members

            public void Add(int item)
            {
                throw new NotSupportedException();
            }

            public void Clear()
            {
                throw new NotSupportedException();
            }

            public bool Contains(int item)
            {
                TValue val;
                return this.dic.TryGetValue(item, out val);
            }

            public void CopyTo(int[] array, int arrayIndex)
            {
                int index = 0;
                int len = array.Length;
                foreach (int i in dic)
                {
                    if (index + arrayIndex > len)
                        break;
                    array[index + arrayIndex] = i;
                    index++;
                }
            }

            public int Count
            {
                get { return this.dic.Count ; }
            }

            public bool IsReadOnly
            {
                get { return true; }
            }

            public bool Remove(int item)
            {
                throw new NotSupportedException();
            }

            #endregion

            #region IEnumerable<int> Members

            public IEnumerator<int> GetEnumerator()
            {
                return dic.GetEnumerator();
            }

            #endregion

            #region IEnumerable Members

            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }

            #endregion
        }

        public bool Remove(int key)
        {
            Contract.Ensures(! ContainsKey(key));
            bool b = _imp.Remove(key);
            return b;
        }

        public bool TryGetValue(int key, out TValue value)
        {
            return _imp.TryGetValue(key, out value);
        }

        public ICollection<TValue> Values
        {
            get { return new FrugalDictionaryCollection<TValue>(_imp); }
        }

        public TValue this[int key]
        {
            get
            {
                TValue result;
                if (!_imp.TryGetValue(key, out result))
                    throw new ArgumentException();
                return result;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        #endregion

        #region ICollection<KeyValuePair<int,TValue>> Members

        public void Add(KeyValuePair<int, TValue> item)
        {
            throw new NotImplementedException();
        }

        public void Clear()
        {
            _imp = new SingleItemDictionary<TValue>();
        }

        public bool Contains(KeyValuePair<int, TValue> item)
        {
            throw new NotImplementedException();
        }

        public void CopyTo(KeyValuePair<int, TValue>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get { return _imp.Count; ; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(KeyValuePair<int, TValue> item)
        {
            return _imp.Remove(item.Key);
        }

        #endregion

        #region IEnumerable<KeyValuePair<int,TValue>> Members

        public IEnumerator<KeyValuePair<int, TValue>> GetEnumerator()
        {
            foreach (int key in _imp)
            {
                TValue val;
                _imp.TryGetValue(key, out val);
                yield return new KeyValuePair<int, TValue>(key, val);
            }
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

        public void AdviseMinMax(int colMic, int colMac)
        {
            int i = colMac - colMic;
            if (i > 128)
            {
                var newDic = new ClusteredDictionary<TValue>();
                transferContentTo(newDic);
                _imp = newDic;
                return;
            }
        }
    }
}
